package pl.common.console;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.beans.factory.DisposableBean;

import pl.model.dao.BookDao;
import pl.model.service.SearchService;

public class Console implements Runnable, DisposableBean {

	protected ObjectPool shellPool;
	protected ServerSocket server = null;

	protected Log log = LogFactory.getLog(getClass());

	protected boolean stop = false;

	public void setServer(ServerSocket server) {
		this.server = server;
	}

	public void setShellPool(ObjectPool shellPool) {
		this.shellPool = shellPool;
	}

	public Console() {
		log
				.info("-------------------------------------creating console object");
		System.out
				.println("-------------------------------------creating console object");

	}

	public static void main(String[] args) {
	}

	@Override
	public void run() {
		log.info("starting console thread");
		try {
			Socket connection = null;
			while (!stop) {
				try {
					connection = server.accept();
					Shell shell = (Shell) shellPool.borrowObject();
					shell.setPool(shellPool);
					shell.setSocket(connection);
					Thread shellThread = new Thread(shell);
					shellThread.setDaemon(true);
					shellThread.start();
				} catch (SocketTimeoutException e) {
					// log.debug("socket timeout - checking stop condition stop:
					// " + stop);
				} catch (NoSuchElementException e) {
					new PrintStream(connection.getOutputStream())
							.println("Server is overloaded, try later");
					connection.getOutputStream().flush();
					connection.close();
				}
			}
			System.out.println("stop " + stop);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
			try {
				System.out.println("server: " + server);
				if (server != null) {
					server.close();
					System.out.println("closing server socket");
					log.info("close");
				}
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}
		log.info("ending console thread");
	}

	public void start() {
		Thread t = new Thread(this);
		t.setDaemon(true);
		t.start();
	}

	public void stop() {
		log.info("stopping console++++++++++++++++++++++++++++++++++++");
		this.stop = true;
		server.notifyAll();
	}

	@Override
	public void destroy() throws Exception {
		log.info("destroy++++++++++++++++++++++++++++++++++++");
		this.stop = true;
		server.notifyAll();
	}

	public void stopDestroy() throws Exception {
		log.info("stopDestroy++++++++++++++++++++++++++++++++++++");
		this.stop = true;
		server.notifyAll();
	}

	public static class BasePoolableShellFactory extends
			BasePoolableObjectFactory {

		protected Map map;
		protected Log log = LogFactory.getLog(getClass());

		public Object makeObject() throws Exception {
			return new Shell(map);
		}

		public void setMap(Map map) {
			this.map = map;
		}
	}
}
